package de.tabuma.soap.logik;

import java.util.logging.*;
import java.lang.reflect.*;
import de.tabuma.soap.annotation.*;
import org.xml.sax.*;
import javax.xml.namespace.*;

/**
 * Methods for attributes
 * @author $Author: alefen $
 * @version $Revision: 1.1 $
 * @since $Date: 2009/12/30 02:53:55 $
 */
public class ObjectAttributeFacade {

    private static Logger log = Logger.getLogger(ObjectAttributeFacade.class.getName());

    /**
     * Gets all attribute as a string in format $attribute="$value" $attribute="$value"
     * @param object
     * @return
     */
    public static String getAttribute(Object object) {
        String str = "";

        for(int i=0;i<object.getClass().getDeclaredFields().length;i++) {
            Field field = object.getClass().getDeclaredFields()[i];
            SoapAttribute soapAttribute = field.getAnnotation(SoapAttribute.class);
            if(soapAttribute!=null) {
                try {
                    Method method = object.getClass().getMethod(ObjectMethods.getGetter(field.getName()));

                    if(method.getReturnType().toString().equals(String.class.toString())) {
                        String a = (String )object.getClass().getMethod(ObjectMethods.getGetter(field.getName())).invoke(object);
                        if(a!=null) {
                            str += field.getName() + "=" + "\"" + a + "\" ";
                        }
                    }
                    if(method.getReturnType().toString().equals(QName.class.toString())) {
                        QName a = (QName) object.getClass().getMethod(ObjectMethods.getGetter(field.getName())).invoke(object);
                        if(a!=null) {
                            str += field.getName() + "=" + "\"" + a.getPrefix() + ":" + a.getLocalPart()  + "\" ";
                        }
                    }
                }
                catch(Exception e) {

                }
            }
        }
        return str;
    }

    /**
     * Sets the attributes of an object (object) to the values that were definined in attribute list (atts).
     * If the object does not habe the setter method for attribute for the object.
     * @param atts Attribute (=Liste of sax attributes)
     * @param obj (Object)
     * @throws org.xml.sax.SAXException
     */
    public static void setAttributes(Attributes atts, Object obj) {

        //checking for extends classes
        for(int i=0;i<obj.getClass().getDeclaredFields().length;i++) {
            try {
                Field field = obj.getClass().getDeclaredFields()[i];
                SoapExtendsDefinition soapExtendsDefinition = field.getAnnotation(SoapExtendsDefinition.class);
                if(soapExtendsDefinition!=null) {
                    Long id = (Long) obj.getClass().getMethod(ObjectMethods.getGetter(field.getName())).invoke(obj);
                    if(id==0) {
                        Object obj1 = soapExtendsDefinition.extendsClass().getConstructors()[0].newInstance();
                        id = PMF.doCreate(obj1);
                        obj.getClass().getMethod(ObjectMethods.getSetter(field.getName()),Long.class).invoke(obj, id);
                        PMF.doUpdate(obj);
                        setAttributes(atts,obj1);
                    }
                    else {
                        Object obj1 = PMF.get(id, soapExtendsDefinition.extendsClass().getConstructors()[0].newInstance());
                        setAttributes(atts,obj1);
                    }

                }
            }
            catch(Exception e) {
                log.warning(e.getMessage());
                String warning = "";
                for(int i1=0;i1<e.getStackTrace().length;i1++) {
                    warning += e.getStackTrace()[i1]+"\n";
                }
                log.warning(warning);
            }
        }

        String warningString = obj+"\n";
        for(int t=0;t<atts.getLength();t++) {
            String localname = atts.getLocalName(t);
            String qname = atts.getQName(t);
            String type = atts.getType(t);
            String uri = atts.getURI(t);
            String value = atts.getValue(t);
            warningString += localname+"|"+qname+"|"+type+"|"+uri+"|"+value+"\n";
        }
        log.fine(warningString);
        log.fine("size:"+obj.getClass().getDeclaredFields().length+"/"+obj);

        // setting the field parameter
        boolean madeChanges = false;
        for(int i=0;i<obj.getClass().getDeclaredFields().length;i++) {
            Field field = obj.getClass().getDeclaredFields()[i];
            SoapAttribute soapAttribute = field.getAnnotation(SoapAttribute.class);
            if(soapAttribute!=null) {
                String fieldName = field.getName();
                if(soapAttribute.fieldName()!=null) {
                    if(!soapAttribute.fieldName().equals("")) {
                        fieldName = soapAttribute.fieldName();
                    }
                    int index = atts.getIndex(fieldName);
                    if(index!=-1) {
                        String getter = ObjectMethods.getGetter(fieldName);
                        String value = atts.getValue(index);
                        String qname = atts.getQName(index);
                        String type = atts.getType(index);
                        String uri = atts.getURI(index);
                        log.fine("fieldname: "+fieldName+" | index: "+index+" | value: "+value+" | qname: "+qname + "|type="+type+"|uri:"+uri);
                        try {

                            Method method = obj.getClass().getMethod(getter);
                            String setter = ObjectMethods.getSetter(fieldName);
                            log.fine(obj+"/"+fieldName+"/"+method.getReturnType().toString());
                            log.fine(getter+":"+method.invoke(obj));
                            if(method.getReturnType().toString().equals(String.class.toString())) {
                                Method setMethod = obj.getClass().getMethod(setter, String.class);
                                setMethod.invoke(obj, value);
                                madeChanges = true;
                            }
                            if(method.getReturnType().toString().equals(QName.class.toString())) {
                                Method setMethod = obj.getClass().getMethod(setter, QName.class);
                                String split[] = value.split(":");
                                QName qName = new QName(split[0],split[1]);
                                setMethod.invoke(obj, qName);
                                log.fine("ha1/"+qName);
                                madeChanges = true;
                            }
                            log.fine(getter+":"+method.invoke(obj));
                        }
                        catch(Exception e) {
                            log.warning(e.getMessage()+"/"+e.getCause()+"/"+e.getClass());
                            String warning = "";
                            for(int f=0;f<e.getStackTrace().length;f++) {
                                warning += e.getStackTrace()[f]+"\n";
                            }
                            log.warning(warning);
                        }
                    }
                }
            }
        }

        if(madeChanges) {
            PMF.doUpdate(obj);
        }
    }
}
